﻿using System;
using System.Collections;
using System.Text;
using FinalProjectLogicLayer;
using Clustering;

namespace FinalProjectLogicLayerINTERFACE
{


    public class LogicLayerImplementation : LogicLayerInterface
    {

        /// <summary>
        /// Progress bar that is used by the gui will be used to display programs progress while running analysis
        /// </summary>
        private System.Windows.Forms.ProgressBar programProgresBar = null;
        /// <summary>
        /// Tool strip status label used by the gui
        /// </summary>
        private System.Windows.Forms.Label toolStripStatusLabel = null;
        /// <summary>
        /// Property for setting or getting the toolStripStatus label
        /// </summary>
        public System.Windows.Forms.Label ToolStripStatusLabel
        {
            get { return toolStripStatusLabel; }
            set { toolStripStatusLabel = value; }
        }
        /// <summary>
        /// This is a list that holds all the input files and their info of this current run
        /// </summary>
        private FileList listOfFileInProcess = new FileList();

        /// <summary>
        /// This is the info of the file that it's information was retrived from the file list
        /// </summary>
        private FileInfo selectedFileInfo = null;

        /// <summary>
        /// This is the dictionary that will be used in this process
        /// </summary>
        private Dictionary dictionaryForFeatureExtraction = new Dictionary();
        /// <summary>
        /// This method returns the path of the last file retrived from the list of files in project
        /// </summary>
        /// <returns>path of the file</returns>
        public String getSelectedFilePath()
        {
            if (selectedFileInfo == null)
                throw new System.NullReferenceException();
            return selectedFileInfo.FilePath;
        }

        public System.Windows.Forms.ProgressBar ProgramProgresBar
        {
            get
            {
                return programProgresBar;
            }
            set
            {
                programProgresBar = value;
            }
        }
        
        /// <summary>
        /// Get the file from the list of files in the process
        /// </summary>
        /// <param name="filePath"></param>
        public void setSelectedFile(String filePath)
        {
            selectedFileInfo = listOfFileInProcess.get(filePath); //method retunes null
        }

        public FeatureExtraction FeatureExtraction
        {
            get
            {
                this.extractFeatures();
                throw new System.NotImplementedException(); //TODO feature extrauc may be an uneccery property
            }
            set
            {
            }
        }
        /// <summary>
        /// get's an array list of dataPoint arranged in arrays each array represents a cluster
        /// the clustering method was PAM
        /// </summary>
        public ArrayList PamClustering
        {
            get
            {
                Clustering.PamClustering.ProgramProgresBar = programProgresBar; //set progress bar
                Clustering.PamClustering.ToolStripStatusLabel = toolStripStatusLabel;

                ArrayList clusteringResult = Clustering.PamClustering.execute(listOfFileInProcess.getCsvVectores(), this.NumberOfClusters, this.VectorDistanceCalculationMethod);
                return listOfFileInProcess.getClusters(clusteringResult);
            }
            set
            {
            }
        }

        private DistanceMeasurement vectorDistanceCalculationMethod = DistanceMeasurement.ManhattanDistance;
        /// <summary>
        /// This will be the distance mesuaring tecnique to calculate distances between vectors
        /// </summary>
        public DistanceMeasurement VectorDistanceCalculationMethod
        {
            get
            {
                Console.WriteLine("LogicLayer: getting distance calculation method: " + vectorDistanceCalculationMethod);

                return vectorDistanceCalculationMethod;

            }
            set
            {
                vectorDistanceCalculationMethod = value;
                Console.WriteLine("LogicLayer: getting distance calculation method: " + vectorDistanceCalculationMethod);
            }
        }

        private int numberOfClusters;
        /// <summary>
        /// This will be the number of cluster that the clustering algorithem will produce
        /// </summary>
        public int NumberOfClusters
        {
            get
            {
                Console.WriteLine("LogicLayer: getting number of clusters " + numberOfClusters);
                return numberOfClusters;
            }
            set
            {
                numberOfClusters = value;
                Console.WriteLine("LogicLayer: setting number of clusters " + numberOfClusters);
            }
        }

        /// <summary>
        /// This is the size of the dictionery that will be used to classify the cipher texts
        /// </summary>
        public int DictionarySize
        {
            get
            {

                Console.WriteLine("LogicLayer: getting dictionary  size " + dictionaryForFeatureExtraction.DictionarySize);
                return dictionaryForFeatureExtraction.DictionarySize;
            }
            set
            {
                dictionaryForFeatureExtraction.DictionarySize = value;
                Console.WriteLine("LogicLayer: setting dictionary  size " + dictionaryForFeatureExtraction.DictionarySize);
            }
        }


        /// <summary>
        /// Size of the dictionary words in characters
        /// </summary>
        public int DictionaryWordSize
        {
            get
            {

                Console.WriteLine("LogicLayer: Sending dictionary word size " + dictionaryForFeatureExtraction.WordSize);
                return dictionaryForFeatureExtraction.WordSize;
            }
            set
            {
                dictionaryForFeatureExtraction.WordSize = value;
                Console.WriteLine("LogicLayer: setting dictionary word size " + dictionaryForFeatureExtraction.WordSize);
            }
        }

        private int stringMatchingErrorsAllowed = 0;
        /// <summary>
        /// This is the max distance allowed between words while searching for dictionary words in texts
        /// (without inserts)
        /// </summary>
        /// <value>0</value>
        public int StringMatchingErrorsAllowed
        {
            get
            {
                Console.WriteLine("LogicLayer: getting string matching distance allowed: " + stringMatchingErrorsAllowed);
                return stringMatchingErrorsAllowed;
            }
            set
            {
                if (value != stringMatchingErrorsAllowed)
                {
                    listOfFileInProcess.StringMachingDistanceUsed = value;
                    stringMatchingErrorsAllowed = value;
                }
                Console.WriteLine("LogicLayer: setting string matching distance allowed: " + stringMatchingErrorsAllowed);
            }
        }


        #region LogicLayerInterface Members
        private String saveFileName = "Untitled.xml";
        public String SaveFileName
        {
            get { return saveFileName; }
            set { saveFileName = value; }
        }

        public void saveFile()
        {
            xmlHandler.saveFile(saveFileName, listOfFileInProcess, dictionaryForFeatureExtraction, stringMatchingErrorsAllowed, vectorDistanceCalculationMethod, numberOfClusters, "PAM", "COMMENTS", "LABLES");
            
        }
        

        public void loadFile(String filePath)
        {
            selectedFileInfo = null;

            listOfFileInProcess.Clear();
            listOfFileInProcess =  xmlHandler.LoadFilelist(filePath);
            bool validFileList = listOfFileInProcess.ValidCSVs;
            dictionaryForFeatureExtraction = xmlHandler.LoadDictionary(filePath);
            FeatureExtraction.AlphaBetSize = dictionaryForFeatureExtraction.DictionaryAlphaBetSize;

            String[] SettingsString = xmlHandler.loadStringMatchingSettings(filePath);

            this.StringMatchingErrorsAllowed = int.Parse(SettingsString[0]);
            this.VectorDistanceCalculationMethod = (Clustering.DistanceMeasurement)Enum.Parse(typeof(Clustering.DistanceMeasurement), SettingsString[1], true);

            SaveFileName = filePath;
            
            SettingsString = xmlHandler.loadClusteringSettings(filePath);
            this.numberOfClusters = int.Parse(SettingsString[1]);
            listOfFileInProcess.ValidCSVs = validFileList;
            //TODO: add clustering name            

        }

        /// <summary>
        /// This method calls the feature extruction features
        /// </summary>
        public void extractFeatures()
        {
            Console.WriteLine("Extract feature called");
            FeatureExtraction.ProgresBar = programProgresBar;
            FeatureExtraction.ToolStripStatusLabel = toolStripStatusLabel;

            FeatureExtraction.calculate(listOfFileInProcess, dictionaryForFeatureExtraction, stringMatchingErrorsAllowed);
            //FeatureExtraction.calculateNoMultiThreading(listOfFileInProcess, dictionaryForFeatureExtraction, stringMatchingErrorsAllowed);
            Console.WriteLine("Feature extraction completed");
        }

        public ArrayList calulateClusters()
        {
            Console.WriteLine("calculate clusters called"); //TODO enable multipile clustering methods
            return this.PamClustering;
        }


        /// <remarks>This method removes a label form the programs database</remarks>
        public bool removeLabel(String labelToRemove)
        {
            Console.WriteLine("LogicLayer: removing label: " + labelToRemove);
            return false;
        }

        /// <summary>
        /// Add a file to process don't allow duplicates
        /// </summary>
        /// <param name="filepath"></param>
        public bool addFileToProcess(String filepath)
        {
            if (listOfFileInProcess.get(filepath) != null) //file allready in the list
                return false;
            listOfFileInProcess.Add(new FileInfo(filepath));
            Console.WriteLine("logic layer: adding file " + filepath);
            return true;
        }

        /// <summary>
        /// This methods removes a file from the current process
        /// </summary>
        /// <param name="?"></param>
        public bool removeFileFromProcess(String filepath)
        {
            if (listOfFileInProcess.get(filepath) == null) //file does not exsist
                return false;

            if (selectedFileInfo.FilePath.Equals(filepath)) //if the last file that was selected is the one removed then update the refrence
                selectedFileInfo = null;

            listOfFileInProcess.Remove(filepath);

            Console.WriteLine("LogicLayer: removing file " + filepath);
            return true;
        }

        public string[] getLabels()
        {
            try
            {
                String path = System.Environment.CurrentDirectory;

                return xmlHandler.loadSavedLables(path+"\\lables.dat");
            }
            catch
            {
                return null;
            }
        }

        #endregion

        public String DictionarySourceFile
        {
            get
            {

                Console.WriteLine("LogicLayer: getting dictionary source file: " + dictionaryForFeatureExtraction.SourceFileName);
                return dictionaryForFeatureExtraction.SourceFileName;
            }
            set
            {
                dictionaryForFeatureExtraction.SourceFileName = value;
                Console.WriteLine("LogicLayer: setting dictionary source file: " + dictionaryForFeatureExtraction.SourceFileName);
            }
        }

        #region LogicLayerInterface Members

        /// <summary>
        /// This methods resets the process and clears all stored data
        /// </summary>
        public void newFile()
        {
            SaveFileName = "";
            selectedFileInfo = null;
            listOfFileInProcess.Clear();
            dictionaryForFeatureExtraction.DictionaryWords = null;
            dictionaryForFeatureExtraction.SourceFileName = "";

            
        }

        #endregion

        /// <summary>
        /// This method returns the file devision parameter of the last file retrived from the list of files in project
        /// </summary>
        public int SelectedFileDevisionParameter
        {
            get
            {
                if (selectedFileInfo == null)
                    throw new System.NullReferenceException();
                return selectedFileInfo.DivisionParameter;
            }
            set
            {
                if (selectedFileInfo != null) 
                    selectedFileInfo.DivisionParameter = value;
            }
        }

        /// <summary>
        /// This method returns the Label of the last file retrived from the list of files in project
        /// </summary>
        public String SelectedFileLabel
        {
            get
            {
                if (selectedFileInfo == null)
                    throw new System.NullReferenceException();
                return selectedFileInfo.Label;
            }
            set
            {
                selectedFileInfo.Label = value;
            }
        }

        /// <summary>
        /// This method returns the Comments of the last file retrived from the list of files in project
        /// </summary>
        public String SelectedFileComments
        {
            get
            {
                if (selectedFileInfo == null)
                    throw new System.NullReferenceException();
                return selectedFileInfo.Comments;
            }
            set
            {
                if (selectedFileInfo == null)
                    throw new System.NullReferenceException();
                selectedFileInfo.Comments = value;
            }
        }
        /// <summary>
        /// This method returns an array of string containing all the 
        /// </summary>
        /// <returns>Retuns a string </returns>
        public String[] getListOfFilesInProcess()
        {
            return listOfFileInProcess.getFileNames();
        }
        /// <summary>
        /// This variable holds a serial number of the dictionary
        /// </summary>
        private long serialNumber;

        public long SerialNumber
        {
            get { return serialNumber; }
            set { serialNumber = value; }
        }

        public void updateLables(String lables)
        {
            xmlHandler.saveLables(lables, "lables.dat");
        }

        public int AlphaBetSize
        {
            get { return FeatureExtraction.AlphaBetSize; }
            set 
            {

                if (listOfFileInProcess.LastSizeOfTheAlphaBet != value)
                {
                    
                    listOfFileInProcess.LastSizeOfTheAlphaBet = value;
                    dictionaryForFeatureExtraction.DictionaryAlphaBetSize = value;
                    FeatureExtraction.AlphaBetSize = value;
                }
            }
        }
        public void generateReport(String filePath,ArrayList guiClusteringResults)
        {
            HtmlReport.createReport(filePath, filePath.Substring(filePath.LastIndexOf('\\') + 1), dictionaryForFeatureExtraction, this.StringMatchingErrorsAllowed, this.VectorDistanceCalculationMethod, NumberOfClusters, "PAM", guiClusteringResults);
        }
        
        /// <summary>
        /// This method writes the vectors calculated by this application to a file in the following format
        /// filename\t
        /// </summary>
        /// <param name="filePath"></param>
        public void exportToTextFileForMatlab(String filePath)
        {
            String csvString = "";
            System.IO.TextWriter tw = new System.IO.StreamWriter(filePath);
            foreach (FileInfo file in listOfFileInProcess)
            {
                int partNumber = 1;
                foreach (double[] CSV in file.FeatureVectors)
                {
                    if (file.FeatureVectors.Count>1)
                        tw.Write(file.FilePath+"_PART"+(partNumber++));
                    else
                        tw.Write(file.FilePath);

                    csvString = "\t";
                    foreach (double num in CSV)
                        csvString += num + "\t";
                    tw.WriteLine(csvString);
                }
            }
            tw.Close();   
        }

    }

}
